﻿using System;
using System.Collections.Generic;
using System.Threading;
using SimpleServiceBus.EndpointManagement.Server;
using SimpleServiceBus.EndpointManagement.Server.Configuration;
using SimpleServiceBus.Messages.Management.Monitoring;
using SimpleServiceBus.Persistence.Domain.Management.Repositories;
using SimpleServiceBus.Tests.Stubs;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;

namespace SimpleServiceBus.Tests.Server
{
    [TestFixture]
    public class EndpointManagementServerServiceTestFixture
    {
        private static TestEndpoint CreateEndpoint()
        {
            var endpoint = TestEndpoint.ConfigureEndpoint();

            EndpointMonitorConfiguration.ConfigureEndpointAsEndpointMonitor(endpoint,
                                                                            TimeSpan.FromMinutes(10),
                                                                            TimeSpan.FromMinutes(10));

            endpoint.RegisterService<IEndpointStatusRepository, TestStatusRepository>();

            return endpoint.Endpoint as TestEndpoint;
        }

        [Test]
        public void ProcessIncomingMessages()
        {

            TestEndpoint endpoint = CreateEndpoint();
            var svc = (EndpointMonitorServer) endpoint.LocalServices.GetService<IEndpointMonitorServerService>();
            var bus = (TestBus) endpoint.MessageBus;
            bus.PublishedMessages.Clear();
            bus.SentMessages.Clear();

            endpoint.Start();

            var onlineMessage = new EndpointOnlineNotification
                                    {
                                        EndpointID = "testid"
                                    };

            bus.ReceiveMessage(onlineMessage);

            List<EndpointMonitorServer.ActiveEndpoint> endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));

            Assert.That(endpoints[0].EndpointID, Is.EqualTo("testid"));
            Assert.AreSame(endpoints[0].LastStatus, onlineMessage);

            var statusMessage = new EndpointStatusUpdateNotification
                                    {
                                        EndpointID = "testid",
                                        StatusExpirationUtcTime = DateTime.Now.ToUniversalTime().AddMilliseconds(60)
                                    };

            svc.EndpointMonitorInterval = TimeSpan.FromMilliseconds(50);

            bus.ReceiveMessage(statusMessage);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));

            Assert.That(endpoints[0].LastStatus, SyntaxHelper.Not.Null);
            Assert.AreSame(endpoints[0].LastStatus, statusMessage);

            Thread.Sleep(500);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(0));

            Assert.That(bus.PublishedMessages.Count, Is.EqualTo(2));


            statusMessage.StatusExpirationUtcTime = DateTime.Now.ToUniversalTime().AddMinutes(1);
            bus.ReceiveMessage(statusMessage);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));


            Thread.Sleep(100);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));

            var offlineNotification = new EndpointOfflineNotification
                                          {
                                              EndpointID = "testid"
                                          };

            bus.ReceiveMessage(offlineNotification);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(0));

            Assert.That(bus.PublishedMessages.Count, Is.EqualTo(3));

            endpoint.Stop();
        }

        [Test]
        public void StartStopTest()
        {

            TestEndpoint endpoint = CreateEndpoint();
            var svc = endpoint.LocalServices.GetService<IEndpointMonitorServerService>();


            endpoint.Start();
            Assert.IsTrue(svc.IsRunning);
            endpoint.Stop();
            Assert.IsFalse(svc.IsRunning);
        }
    }
}